package com.cjq.core;


import com.cjq.conf.MinioConf;
import com.cjq.conf.MinioConfProperties;
import com.cjq.constant.ContentType;
import com.cjq.define.MinioServiceInterface;
import io.minio.MinioClient;
import io.minio.ObjectStat;
import io.minio.PutObjectArgs;
import io.minio.messages.Part;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Import;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Objects;
import java.util.UUID;

/**
 * MinIO服务实现类，提供文件上传和URL转换功能
 * 依赖注入MinioClient客户端和MinioConf配置类
 */
@Slf4j
@Import(MinioConf.class)
public class MinioServer implements MinioServiceInterface {

    /**
     * MinIO客户端实例，用于执行对象存储操作
     */
    @Autowired
    private MinioClient minioClient;

    /**
     * MinIO配置属性，包含地址、公网地址等配置信息
     */
    @Autowired
    private MinioConfProperties properties;

    /**
     * 将内部网络URL转换为公网可访问URL
     *
     * @param url 需要转换的内部网络URL
     * @return 转换后的公网URL
     * @throws IllegalArgumentException 当url参数为空或未配置公网地址时抛出
     */
    @Override
    public String getPublicURL(String url) {
        // 参数校验
        if (StringUtils.isBlank(url)) {
            throw new IllegalArgumentException("参数不能为null或空白");
        }
        if (StringUtils.isBlank(properties.getPublicAddress())) {
            throw new IllegalArgumentException("未配置公网地址publicAddress");
        }

        // 执行URL地址替换
        return url.replace(properties.getAddress(), properties.getPublicAddress());
    }

    /**
     * 上传文件流到指定存储桶<br>
     * 注意：若原始文件名包含扩展名，则即使配置了ContentType，也默认使用原始文件扩展名类型
     *      若原始文件名不包含扩展名，则使用ContentType扩展名类型
     * @param bucketName 存储桶名称
     * @param originalFilename 原始文件名
     * @param stream 文件输入流
     * @param contentType 文件内容类型
     * @return 文件访问路径
     * @throws RuntimeException 当上传过程出现异常时抛出
     */
    @Override
    public String uploadFile(String bucketName, String originalFilename, InputStream stream, ContentType contentType) {
        try {
            // 生成唯一对象名称
            String objectName = generateObjectName(originalFilename, contentType.getExtension());

            // 执行文件上传操作
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .stream(stream, stream.available(), -1)
                            .contentType(contentType.getType())
                            .build());

            // 构建访问URL
            return properties.getAddress() + "/" + bucketName + "/" + objectName;
        } catch (Exception e) {
            log.error("minio put object error:", e);
            throw new RuntimeException("上传文件失败");
        }
    }

    /**
     * 上传MultipartFile到指定存储桶
     *
     * @param bucketName 存储桶名称
     * @param file 待上传的MultipartFile文件
     * @return 文件访问路径
     * @throws RuntimeException 当上传过程出现异常时抛出
     */
    @Override
    public String uploadFile(String bucketName, MultipartFile file) {
        try {
            // 生成唯一对象名称
            String objectName = generateObjectName(Objects.requireNonNull(file.getOriginalFilename()));

            // 执行文件上传操作
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .stream(file.getInputStream(), file.getSize(), -1)
                            .contentType(file.getContentType())
                            .build());

            // 构建访问URL
            return properties.getAddress() + "/" + bucketName + "/" + objectName;
        } catch (Exception e) {
            log.error("minio put object error:", e);
            throw new RuntimeException("上传文件失败");
        }
    }

    /**
     * 生成唯一对象存储路径
     *
     * @param originalFilename 原始文件名
     * @param type 文件内容类型
     * @return 生成的唯一对象路径
     */
    private String generateObjectName(String originalFilename, String type) {
        String filePath;
        // 生成UUID作为文件名前缀
        String uuid = UUID.randomUUID().toString().replace("-", "");

        // 处理文件扩展名
        if (originalFilename.lastIndexOf(".") == -1) {
            filePath = uuid + type;
        } else {
            filePath = uuid + originalFilename.substring(originalFilename.lastIndexOf("."));
        }

        // 启用分片时添加日期路径前缀
        if (properties.isSharding()) {
            DateTimeFormatter pattern = DateTimeFormatter.ofPattern(properties.getPattern());
            filePath = LocalDateTime.now().format(pattern) + "/" + filePath;
        }
        return filePath;
    }

    /**
     * 重载方法，使用空字符串作为默认内容类型
     *
     * @param originalFilename 原始文件名
     * @return 生成的唯一对象路径
     */
    private String generateObjectName(String originalFilename) {
        return generateObjectName(originalFilename, "");
    }



    @Override
    public String initMultiPartUpload(String bucketName, String objectName) {
        return "";
    }


    @Override
    public void completeMultiPartUpload(String bucketName, String objectName, String uploadId, List<Part> partETags) {

    }





    @Override
    public InputStream getObject(String bucketName, String objectName) {
        return null;
    }

    @Override
    public void downloadFile(String bucketName, String objectName, String localFilePath) {

    }

    @Override
    public void removeObject(String bucketName, String objectName) {

    }

    @Override
    public void removeObjects(String bucketName, List<String> objectNames) {

    }

    @Override
    public ObjectStat getObjectInfo(String bucketName, String objectName) {
        return null;
    }



    @Override
    public boolean bucketExists(String bucketName) {
        return false;
    }

    @Override
    public void makeBucket(String bucketName) {

    }

}
